package com.stox.ui.javafx.charting.model.plot;

import java.util.ArrayList;
import java.util.List;

import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.scene.canvas.Canvas;
import javafx.scene.paint.Color;

import org.controlsfx.control.PopOver;

import com.stox.dto.AbstractModel;
import com.stox.dto.preference.PreferenceFactory;
import com.stox.dto.web.BeanDescriptor;
import com.stox.ui.javafx.charting.model.ChartingPreference;
import com.stox.ui.javafx.charting.model.uiunit.AbstractUiUnit;
import com.stox.ui.javafx.charting.strategy.Strategy;
import com.stox.ui.javafx.charting.widget.Chart;

public abstract class AbstractPlot<T, 
			W extends Chart<U>, 
			V extends AbstractUiUnit<T,W, V, U>, 
			U extends AbstractPlot<T,W,V,U>>{
	
	private W chart;
	
	private final AbstractModel model;
	
	private final List<T> data = new ArrayList<>();
	
	private final List<V> uiUnits = new ArrayList<>();
	
	/**
	 * Color of the plot.
	 * This is a convenient place for all UI Units to share the color is they all have the same color.
	 * This property can be null for the plots that have multiple color.
	 */
	private ObjectProperty<Color> colorProperty;
	public ObjectProperty<Color> colorProperty(){
		if(null == colorProperty){
			colorProperty = new SimpleObjectProperty<>();
		}
		return colorProperty;
	}
	public Color getColor(){
		return null == colorProperty ? null : colorProperty.get();
	}
	public void setColor(Color color){
		colorProperty().set(color);
	}
	
	private Strategy<V> colorStrategy;
	
	private Strategy<V> widthStrategy;
	
	private Strategy<V> heightStrategy;
	
	private Strategy<V> backgroundColorStrategy;
	
	protected double highest = Double.MIN_VALUE;
	
	protected double lowest = Double.MAX_VALUE;
	
	/**
	 * The beanDescriptor for configuration of this plot. 
	 * This can be beanDescriptor for configuration of the indicator/screen.
	 */
	private ObjectProperty<BeanDescriptor> configurationBeanDescriptor;
	public ObjectProperty<BeanDescriptor> configurationBeanDescriptorProperty(){
		if(null == configurationBeanDescriptor){
			configurationBeanDescriptor = new SimpleObjectProperty<BeanDescriptor>();
		}
		return configurationBeanDescriptor;
	}
	public BeanDescriptor getConfigurationBeanDescriptor(){
		return null == configurationBeanDescriptor ? null : configurationBeanDescriptor.get();
	}
	public void setConfigurationBeanDescriptor(BeanDescriptor configurationBeanDescriptor){
		configurationBeanDescriptorProperty().set(configurationBeanDescriptor);
	}
	
	
	/**
	 * ConfigurationUI for this plot
	 * User interface for the configuration object.
	 * This UI should be auto-generated once, then cached.
	 */
	private ObjectProperty<PopOver> configurationUI;
	public ObjectProperty<PopOver> configurationUIProperty(){
		if(null == configurationUI){
			configurationUI = new SimpleObjectProperty<>();
		}
		return configurationUI;
	}
	public PopOver getConfigurationUI(){
		return configurationUI == null ? null : configurationUI.get();
	}
	public void setConfigurationUI(PopOver popOver){
		configurationUIProperty().set(popOver);
	}
	
	public AbstractPlot(AbstractModel model) {
		this.model = model;
	}
	
	protected abstract void createUiUnits();

	public void update() {
		reset();
	}
	
	public abstract void paint();
	
	public void paintBackground() {
		if(getBackgroundColorStrategy() == null) {
			Canvas canvas = getChart().getCanvas();
			canvas.getGraphicsContext2D().setFill(PreferenceFactory.get(ChartingPreference.class).getBackgroundColor());
			canvas.getGraphicsContext2D().fillRect(canvas.getLayoutX(), canvas.getLayoutY(), canvas.getWidth(), canvas.getHeight());
		}else {
			for(int index = getChart().getChartingView().getEndIndex()-1; 
					index >= getChart().getChartingView().getStartIndex(); index--) {
				getUiUnits().get(index).paintBackground();
			}
		}
	}
	
	public void reset() {
		highest = Double.MIN_VALUE;
		lowest = Double.MAX_VALUE;
	}
	
	public AbstractModel getModel() {
		return model;
	}
	
	public W getChart() {
		return chart;
	}

	public void setChart(W chart) {
		this.chart = chart;
	}

	public double getHighest() {
		return highest;
	}

	public double getLowest() {
		return lowest;
	}

	public List<T> getData() {
		return data;
	}

	public void setData(List<T> data) {
		if(this.data != data){
			this.data.clear();
			this.data.addAll(data);
		}
		uiUnits.clear();
		createUiUnits();
	}

	public List<V> getUiUnits() {
		return uiUnits;
	}

	public Strategy<V> getColorStrategy() {
		return colorStrategy;
	}

	public void setColorStrategy(
			Strategy<V> colorStrategy) {
		this.colorStrategy = colorStrategy;
	}

	public Strategy<V> getWidthStrategy() {
		return widthStrategy;
	}

	public void setWidthStrategy(Strategy<V> widthStrategy) {
		this.widthStrategy = widthStrategy;
	}

	public Strategy<V> getHeightStrategy() {
		return heightStrategy;
	}

	public void setHeightStrategy(Strategy<V> heightStrategy) {
		this.heightStrategy = heightStrategy;
	}
	
	public Strategy<V> getBackgroundColorStrategy() {
		return backgroundColorStrategy;
	}

	public void setBackgroundColorStrategy(
			Strategy<V> backgroundColorStrategy) {
		this.backgroundColorStrategy = backgroundColorStrategy;
	}

	
}
